package dat255.calendarclock.controller;

import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Observer;

import android.app.Activity;
import android.content.Intent;
import android.gesture.Gesture;
import android.gesture.GestureOverlayView;
import android.gesture.GestureStroke;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import dat255.calendarclock.R;
import dat255.calendarclock.controller.event.ShowEventController;
import dat255.calendarclock.model.event.DateHelper;
import dat255.calendarclock.model.event.Event;
import dat255.calendarclock.model.event.EventHandler;
import dat255.calendarclock.model.event.SubEvent;
import dat255.calendarclock.view.ListCalendarView;
import dat255.calendarclock.view.MonthCalendarDateButton;

/**
 * 
 * Controlls the monthly tab.
 * 
 * @author Marcus
 *
 */
public class MonthCalendarController extends Activity implements Observer{

	// Field
	
	// Selection mode
	public static final int SELECTIONMODE_SINGLE = 0;
	public static final int SELECTIONMODE_MULTIPLE = 1;
	
	public int selectionMode = 0;
	
	// Used for multiple selection mode
	private LinkedList<Integer> selectedIndexes = new LinkedList<Integer>();
	
	private static float GESTURE_SCALE = 2/5f;

	// A list that holds all the buttons, each representing a day
	private LinkedList<MonthCalendarDateButton> dateButtons = new LinkedList<MonthCalendarDateButton>();
	private int selectedButtonIndex = 0;

	// Reference to the list to display events on the chosen day.
	private ListCalendarView listView;
	
	// Capture the gestures for switching month
	private GestureOverlayView.OnGesturePerformedListener gestureListener = new GestureOverlayView.OnGesturePerformedListener() {

		@Override
		public void onGesturePerformed(GestureOverlayView overlay,
				Gesture gesture) {
			
			for (GestureStroke stroke : gesture.getStrokes()) {
				if (stroke.points.length < 25
						& stroke.length > GESTURE_SCALE
								* findViewById(R.id.MonthCalendarGridView)
										.getWidth()) {
					float deltaX = stroke.points[0] - stroke.points[stroke.points.length - 1];
					int monthDelta = (int) (deltaX / Math.abs(deltaX));

					EventHandler eventHandler = EventHandler.getInstance();
					
					GregorianCalendar selectedDay = eventHandler.getSelectedDay();
					selectedDay.add(GregorianCalendar.MONTH, monthDelta);
					eventHandler.setSelectedDay(selectedDay);
				}
			}

		}
	};

	// System state handeling
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.monthview_layout);

		EventHandler.getInstance().addObserver(this);
		
		// Map all xmlbuttons to the array
		mapButtons();

		// Assign a gesture detector
		GestureOverlayView gestureOverlay = (GestureOverlayView) findViewById(R.id.MonthCalendarGestureOverlay);
		gestureOverlay.addOnGesturePerformedListener(gestureListener);
		gestureOverlay.setGestureColor(Color.TRANSPARENT);
		gestureOverlay.setUncertainGestureColor(Color.TRANSPARENT);
		loadEvents(GregorianCalendar.MONTH);

	}

	@Override
	protected void onResume() {
		update(null, null);
		super.onResume();
	}
	
	// Initialization
	
	/**
	 * Loads this monthly view when the month has changed
	 * 
	 * @param precision
	 */
	public void loadEvents(int precision) {
		
		
		GregorianCalendar selectedDay = EventHandler.getInstance()
				.getSelectedDay();
		
		// Reset to the first day of this month
		GregorianCalendar f = DateHelper.reset((GregorianCalendar) selectedDay.clone(),
				GregorianCalendar.MONTH);
		// Get the weekday of that day
		int fw = (f.get(GregorianCalendar.DAY_OF_WEEK) + 5) % 7;

		int selectedMonth = selectedDay.get(GregorianCalendar.MONTH);
		int selectedDate = selectedDay.get(GregorianCalendar.DATE);

		for (int i = 0; i < 42; i++) {
			int dateNum = i - fw + 1;
			GregorianCalendar date = new GregorianCalendar(
					selectedDay.get(GregorianCalendar.YEAR), selectedMonth,
					dateNum);
			dateButtons.get(i).setDate(date);

			boolean currentMonth = date.get(GregorianCalendar.MONTH) == selectedMonth;

			dateButtons.get(i).setCurrentMonth(currentMonth);

			if (i == 35 && !currentMonth) {
				findViewById(R.id.MonthCalendarLastRow)
						.setVisibility(View.GONE);
				break;
			} else if (i == 35) {
				findViewById(R.id.MonthCalendarLastRow).setVisibility(
						View.VISIBLE);
			}

			if (dateNum == selectedDate && currentMonth) {
				selectedButtonIndex = i;
				dateButtons.get(selectedButtonIndex).toggle();
			}
		}

		listView = (ListCalendarView) findViewById(R.id.monthCalendarListView);
		listView.setShowSeparators(false);
		listView.loadEvents(GregorianCalendar.DATE);
	}

	/**
	 * Maps all xml buttons to and easy access array... Nothing to see here,
	 * move along...
	 */
	private void mapButtons() {
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton01));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton02));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton03));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton04));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton05));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton06));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton07));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton08));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton09));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton10));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton11));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton12));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton13));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton14));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton15));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton16));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton17));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton18));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton19));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton20));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton21));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton22));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton23));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton24));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton25));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton26));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton27));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton28));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton29));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton30));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton31));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton32));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton33));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton34));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton35));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton36));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton37));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton38));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton39));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton40));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton41));
		dateButtons
				.add((MonthCalendarDateButton) findViewById(R.id.MonthCalendarDateButton42));
	}

	// Methods
	
	/**
	 * Method called when a button has been clicked
	 * 
	 * @param view
	 */
	public void dateButtonOnClick(View view) {
		
		if (selectionMode == SELECTIONMODE_SINGLE){
			MonthCalendarDateButton button = (MonthCalendarDateButton) view;
			EventHandler eventHandler = EventHandler.getInstance();
			eventHandler.setSelectedDay(button.getDate());
		}
		else{
			selectedIndexes.add(dateButtons.indexOf((MonthCalendarDateButton) view));
		}
	}
	
	@Override
	public void update(Observable observable, Object data) {
		if(data instanceof Event) {
			return;
		}
		MonthCalendarDateButton previousButton = dateButtons
				.get(selectedButtonIndex);
		previousButton.toggle();
		previousButton.invalidate();
		loadEvents(GregorianCalendar.MONTH);	
	}
	
	public void listItemClicked(View view){
		try{
		SubEvent subEvent= (SubEvent)listView.getItemAtPosition(listView.getPositionForView(view));
		EventHandler.getInstance().setSelectedEvent(subEvent);
		startActivity(new Intent(this,ShowEventController.class));
		}catch (Exception e) {
			Log.d("debug",""+(e.getClass().getName()));
		}
	}

	// Multiple selection
	
	public int getSelectionMode(){
		return this.selectionMode;
	}
	
	public void setSelectionMode(int mode){
		this.selectionMode = mode;
	}
	
	public LinkedList<Integer> getSelectedIndexes(){
		return this.selectedIndexes;
	}
	
}



